use core::str;

use smallvec::SmallVec;

use crate::{RedisError, RedisResult};

use super::{
    Value, CHAR_N, CHAR_R, TAG_ARRAY, TAG_BIG_NUMBER, TAG_BOOL, TAG_BULK_ERROR, TAG_BULK_STRING,
    TAG_DOUBLE, TAG_INTEGER, TAG_MAP, TAG_NIL, TAG_PUSHES, TAG_SET, TAG_SIMPLE_ERROR,
    TAG_SIMPLE_STRING, TAG_VERBATIM_STRING,
};

pub struct FrameBuffer {
    buf: Vec<u8>,
    vals: Vec<Value>,
    pos: usize,
}

impl FrameBuffer {
    pub fn new() -> Self {
        Self {
            buf: Vec::new(),
            vals: vec![],
            pos: 0,
        }
    }

    pub fn put(&mut self, data: &[u8]) {
        // log::trace!("Receive:{data:?}");
        self.buf.extend_from_slice(data);
    }

    pub fn read_next_values(&mut self) -> RedisResult<SmallVec<[Value; 4]>> {
        let mut result = SmallVec::<[Value; 4]>::new();
        loop {
            match self.peek() {
                Some(tag) => {
                    match self.read_next_val_by_tag(tag)? {
                        Some(val) => {
                            if self.vals.len() > 0 {
                                if let Some(val_result) = self.collapse_values_2(val) {
                                    result.push(val_result);
                                }
                            } else if value_is_valid(&val) {
                                result.push(val);
                            } else {
                                self.vals.push(val);
                            }
                            self.buf.drain(0..self.pos);
                            self.pos = 0;
                        }
                        None => {
                            self.pos = 0;
                            break;
                        }
                    }
                }
                None => {
                    break;
                }
            }
        }
        if self.buf.capacity() >= 10240 {
            self.buf.shrink_to_fit();
        }
        Ok(result)
    }

    fn read_next_val_by_tag(&mut self, tag: u8) -> RedisResult<Option<Value>> {
        Ok(match tag {
            TAG_ARRAY => {
                if let Some(size) = self.read_to_line_end_number()? {
                    Some(Value::Array(Vec::with_capacity(size)))
                } else {
                    None
                }
            }
            TAG_MAP => {
                if let Some(size) = self.read_to_line_end_number()? {
                    Some(Value::Map(Vec::with_capacity(size)))
                } else {
                    None
                }
            }
            TAG_SET => {
                if let Some(size) = self.read_to_line_end_number()? {
                    Some(Value::Set(Vec::with_capacity(size)))
                } else {
                    None
                }
            }
            TAG_PUSHES => {
                if let Some(size) = self.read_to_line_end_number()? {
                    Some(Value::Pushes(Vec::with_capacity(size)))
                } else {
                    None
                }
            }
            TAG_INTEGER => {
                if let Some(val) = self.read_to_line_end() {
                    let str_len = std::str::from_utf8(val).map_err(|err| {
                        RedisError::new_resp_deserialize("the integer value is invalid", err)
                    })?;
                    Some(Value::Integer(str_len.parse::<i64>().map_err(|err| {
                        RedisError::new_resp_deserialize(
                            format!("couldn't parse {str_len} to i64"),
                            err,
                        )
                    })?))
                } else {
                    None
                }
            }
            TAG_BIG_NUMBER => {
                if let Some(val) = self.read_to_line_end() {
                    let str_len = std::str::from_utf8(val).map_err(|err| {
                        RedisError::new_resp_deserialize("the big number value is invalid", err)
                    })?;
                    Some(Value::BigNumber(str_len.parse::<i128>().map_err(
                        |err| {
                            RedisError::new_resp_deserialize(
                                format!("couldn't parse {str_len} to i64"),
                                err,
                            )
                        },
                    )?))
                } else {
                    None
                }
            }
            TAG_DOUBLE => {
                if let Some(val) = self.read_to_line_end() {
                    let str_len = std::str::from_utf8(val).map_err(|err| {
                        RedisError::new_resp_deserialize("the double value is invalid", err)
                    })?;
                    Some(Value::Double(str_len.parse::<f64>().map_err(|err| {
                        RedisError::new_resp_deserialize(
                            format!("couldn't parse {str_len} to f64"),
                            err,
                        )
                    })?))
                } else {
                    None
                }
            }
            TAG_SIMPLE_STRING => {
                if let Some(val) = self.read_to_line_end() {
                    // let str = str::from_utf8(val).map_err(|err| {
                    //     RedisError::new_resp_deserialize("the simple string value is invalid", err)
                    // })?;
                    Some(Value::SimpleString(val.to_vec()))
                } else {
                    None
                }
            }
            TAG_BULK_STRING => {
                if let Some(buf_len) = self.read_to_line_end() {
                    let str = str::from_utf8(buf_len).map_err(|err| {
                        RedisError::new_resp_deserialize(
                            "couldn't parse len part of bulk str to string",
                            err,
                        )
                    })?;
                    let len = str.parse::<usize>().map_err(|err| {
                        RedisError::new_resp_deserialize(
                            "couldn't parse len part of bulk str to usize",
                            err,
                        )
                    })?;
                    if let Some(buf_val) = self.read_exact(len, true) {
                        Some(Value::BulkString(buf_val.to_vec()))
                    } else {
                        None
                    }
                } else {
                    None
                }
            }
            TAG_BULK_ERROR => {
                if let Some(buf_len) = self.read_to_line_end() {
                    let str = str::from_utf8(buf_len).map_err(|err| {
                        RedisError::new_resp_deserialize(
                            "couldn't parse len part of bulk error to string",
                            err,
                        )
                    })?;
                    let len = str.parse::<usize>().map_err(|err| {
                        RedisError::new_resp_deserialize(
                            "couldn't parse len part of bulk error to usize,",
                            err,
                        )
                    })?;
                    if let Some(buf_val) = self.read_exact(len, true) {
                        Some(Value::BulkError(buf_val.to_vec()))
                    } else {
                        None
                    }
                } else {
                    None
                }
            }
            TAG_BOOL => {
                if let Some(buf_val) = self.read_to_line_end() {
                    let str = str::from_utf8(buf_val).map_err(|err| {
                        RedisError::new_resp_deserialize(
                            "couldn't parse boolean buffer to string",
                            err,
                        )
                    })?;
                    let res = match str {
                        "t" => true,
                        "f" => false,
                        _ => {
                            return Err(RedisError::RespDeserialize(format!(
                                "the [{str}] is not a valid boolean value"
                            )));
                        }
                    };
                    Some(Value::Boolean(res))
                } else {
                    None
                }
            }
            TAG_VERBATIM_STRING => {
                if let Some(buf_val) = self.read_to_line_end() {
                    let str = str::from_utf8(buf_val).map_err(|err| {
                        RedisError::new_resp_deserialize(
                            "couldn't parse len part of verbatim string to str",
                            err,
                        )
                    })?;
                    let len = str.parse::<usize>().map_err(|err| {
                        RedisError::new_resp_deserialize(
                            "couldn't parse len part of verbatim string to usize",
                            err,
                        )
                    })?;
                    if let Some(data) = self.read_exact(len, true) {
                        let data_len = data.len();
                        if data_len < 5 {
                            return Err(RedisError::RespDeserialize(
                                "the format of verbatim str is invalid".to_string(),
                            ));
                        }
                        let encoding = str::from_utf8(&data[0..3]).map_err(|err| {
                            RedisError::new_resp_deserialize(
                                "couldn't parse encoding part of verbatim str to str",
                                err,
                            )
                        })?;
                        Some(Value::VerbatimString(
                            encoding.to_string(),
                            (&data[5..]).to_vec(),
                        ))
                    } else {
                        None
                    }
                } else {
                    None
                }
            }
            TAG_SIMPLE_ERROR => {
                if let Some(buf_val) = self.read_to_line_end() {
                    // let str = str::from_utf8(buf_val).map_err(|err| {
                    //     RedisError::new_resp_deserialize("couldn't parse to simple error", err)
                    // })?;
                    Some(Value::SimpleError(buf_val.to_vec()))
                } else {
                    None
                }
            }
            TAG_NIL => {
                if let Some(_) = self.read_to_line_end() {
                    Some(Value::Nil)
                } else {
                    None
                }
            }
            _ => None,
        })
    }

    fn peek(&mut self) -> Option<u8> {
        if let Some(byte) = self.buf.get(self.pos) {
            self.pos += 1;
            Some(*byte)
        } else {
            None
        }
    }

    // fn eof(&self) -> RedisError {
    //     RedisError::RespDeserialize(format!("EOF at {}", self.pos))
    // }

    //  fn advance(&mut self, num: usize) {
    //     self.pos += num;
    // }

    fn read_to_line_end(&mut self) -> Option<&[u8]> {
        let start = self.pos;
        loop {
            // let char1 = self.buf.get(cur1);
            // let char2 = self.buf.get(cur2);
            if let Some(c1) = self.buf.get(self.pos) {
                if c1 != &crate::resp::CHAR_R {
                    self.pos += 1;
                    continue;
                }
            } else {
                return None;
            }
            if let Some(c2) = self.buf.get(self.pos + 1) {
                if c2 != &crate::resp::CHAR_N {
                    self.pos += 1;
                    continue;
                }
            } else {
                return None;
            }
            let end = self.pos;
            // if start >= end {
            //     return None;
            // }
            self.pos += 2;
            return Some(&self.buf[start..end]);
        }
    }

    fn read_to_line_end_number(&mut self) -> RedisResult<Option<usize>> {
        if let Some(str_len) = self.read_to_line_end() {
            let res = String::from_utf8_lossy(str_len);
            match res.parse::<usize>() {
                Ok(val) => Ok(Some(val)),
                Err(err) => Err(RedisError::RespDeserialize(format!(
                    "error on parse {res} to usize, {err}"
                ))),
            }
        } else {
            Ok(None)
        }
    }

    fn read_exact(&mut self, len: usize, is_check_end: bool) -> Option<&[u8]> {
        let start = self.pos;
        let end = start + len;
        if self.buf.len() - 1 < end {
            return None;
        }
        let data = &self.buf[start..end];
        self.pos += len;
        if is_check_end {
            match self.buf.get(self.pos) {
                Some(&CHAR_R) => {}
                Some(_) | None => {
                    return None;
                }
            }
            match self.buf.get(self.pos + 1) {
                Some(&CHAR_N) => {}
                Some(_) | None => {
                    return None;
                }
            }
            self.pos += 2;
        }
        Some(data)
    }

    // fn collapse_values(&mut self, val: Value) -> RedisResult<Option<Value>> {
    //     let mut vals_iter = self.vals.iter_mut();
    //     if let Some(last_1) = vals_iter.nth_back(0) {
    //         match last_1 {
    //             Value::Array(array) => {
    //                 array.push(val);
    //                 if array.len() == array.capacity() {
    //                     return Ok(Some(self.vals.remove(self.vals.len() - 1)));
    //                 }
    //                 return Ok(None);
    //             }
    //             Value::Map(map) => {
    //                 if let Some(key) = self.map_key.take() {
    //                     map.insert(key, val);
    //                     if map.len() == map.capacity() {
    //                         let map_owned = self.vals.remove(self.vals.len() - 1);
    //                         return Ok(Some(map_owned));
    //                     } else {
    //                         return Ok(None);
    //                     }
    //                 } else {
    //                     self.map_key.replace(val);
    //                     return Ok(None);
    //                 }
    //             }
    //             Value::Set(set) => {
    //                 set.push(val);
    //                 if set.len() == set.capacity() {
    //                     return Ok(Some(self.vals.remove(self.vals.len() - 1)));
    //                 }
    //                 return Ok(None);
    //             }
    //             Value::Pushes(pushes) => {
    //                 pushes.push(val);
    //                 if pushes.len() == pushes.capacity() {
    //                     return Ok(Some(self.vals.remove(self.vals.len() - 1)));
    //                 }
    //                 return Ok(None);
    //             }
    //             _ => {}
    //         }
    //     }
    //     Ok(None)
    // }

    fn collapse_values_2(&mut self, val: Value) -> Option<Value> {
        self.vals.push(val);
        // let mut len_max = self.vals.len() - 1;
        let mut len_index = self.vals.len();
        // let vals_iter = self.vals.iter();
        loop {
            len_index -= 1;
            match self.vals.get(len_index) {
                Some(Value::Array(array)) => {
                    if array.len() == array.capacity() {
                        continue;
                    }
                    let min = len_index + 1;
                    let len_max = self.vals.len();
                    if len_max - min < array.capacity() {
                        break;
                    }
                    let mut array_item = self.vals.remove(len_index);
                    match &mut array_item {
                        Value::Array(array_inner) => {
                            for _ in min..len_max {
                                array_inner.push(self.vals.remove(min - 1));
                            }
                        }
                        _ => {}
                    }
                    self.vals.push(array_item);
                }
                Some(Value::Map(map)) => {
                    if map.len() == map.capacity() {
                        continue;
                    }
                    let min = len_index + 1;
                    let len_max = self.vals.len();
                    if len_max - min < map.capacity() * 2 {
                        break;
                    }
                    let mut map_item = self.vals.remove(len_index);
                    match &mut map_item {
                        Value::Map(map_inner) => {
                            let mut key = Option::None;
                            for _ in min..len_max {
                                if let Some(key_inner) = key.take() {
                                    let value = self.vals.remove(min - 1);
                                    map_inner.push((key_inner, value));
                                } else {
                                    key.replace(self.vals.remove(min - 1));
                                }
                            }
                        }
                        _ => {}
                    }
                    self.vals.push(map_item);
                }
                Some(Value::Set(set)) => {
                    if set.len() == set.capacity() {
                        continue;
                    }
                    let min = len_index + 1;
                    let len_max = self.vals.len();
                    if len_max - min < set.capacity() {
                        break;
                    }
                    let mut set_item = self.vals.remove(len_index);
                    match &mut set_item {
                        Value::Set(set_inner) => {
                            for _ in min..len_max {
                                set_inner.push(self.vals.remove(min - 1));
                            }
                        }
                        _ => {}
                    }
                    self.vals.push(set_item);
                }
                Some(Value::Pushes(pushes)) => {
                    if pushes.len() == pushes.capacity() {
                        continue;
                    }
                    let min = len_index + 1;
                    let len_max = self.vals.len();
                    if len_max - min < pushes.capacity() {
                        break;
                    }
                    let mut pushes_item = self.vals.remove(len_index);
                    match &mut pushes_item {
                        Value::Pushes(pushes_inner) => {
                            for _ in min..len_max {
                                pushes_inner.push(self.vals.remove(min - 1));
                            }
                        }
                        _ => {}
                    }
                    self.vals.push(pushes_item);
                }
                Some(_) => {}
                None => break,
            }
            if len_index == 0 {
                break;
            }
        }
        if self.vals.len() == 1 {
            Some(self.vals.remove(0))
        } else {
            None
        }
    }
}

// fn is_valid_match_tag(tag: &u8, curosr: &mut Cursor) -> RedisResult<bool> {
//     match tag {
//         &TAG_ARRAY => {}
//         &TAG_MAP => is_valid_map(curosr),
//         &TAG_SET => {}
//         &TAG_PUSH => {}
//         &TAG_BIG_NUMBER | &TAG_INTEGER | &TAG_DOUBLE | &TAG_BOOL | &TAG_SIMPLE_ERROR
//         | &TAG_SIMPLE_STRING | &TAG_NIL => {
//             _ = curosr.read_to_line_end()?;
//             Ok(true)
//         }
//         &TAG_BULK_STRING | &TAG_BULK_ERROR => {
//             _ = curosr.read_bulk_str_data()?;
//             Ok(true)
//         }
//         &TAG_VERBATIM_STRING => true,
//         _ => Err(RedisError::Other("the tag is not valid".to_string())),
//     }
// }

// fn is_valid_map(curosr: &mut Cursor) -> RedisResult<bool> {
//     let len = curosr.read_line_end_integer()?;
//     // valid the elements length
// }

fn value_is_valid(value: &Value) -> bool {
    match value {
        Value::Nil
        | Value::SimpleString(_)
        | Value::Integer(_)
        | Value::BigNumber(_)
        | Value::Double(_)
        | Value::BulkString(_)
        | Value::BulkError(_)
        | Value::Boolean(_)
        | Value::SimpleError(_)
        | Value::VerbatimString(_, _) => true,
        Value::Array(array) => array.len() == array.capacity(),
        Value::Map(map) => map.len() == map.capacity(),
        Value::Set(set) => set.len() == set.capacity(),
        Value::Pushes(pushes) => pushes.len() == pushes.capacity(),
    }
}

// fn get_hashmap_key(value: &Value) -> RedisResult<&str> {
//     match value {
//         Value::Nil => Err(RedisError::RespDeserialize(
//             "nil value could't be hash key".to_string(),
//         )),
//         Value::Array(_) => Err(RedisError::RespDeserialize(
//             "array value could't be hash key".to_string(),
//         )),
//         Value::Map(_) => Err(RedisError::RespDeserialize(
//             "map value could't be hash key".to_string(),
//         )),
//         Value::Set(_) => Err(RedisError::RespDeserialize(
//             "set value could't be hash key".to_string(),
//         )),
//         Value::Pushes(_) => Err(RedisError::RespDeserialize(
//             "pushes value could't be hash key".to_string(),
//         )),
//         Value::Integer(_) => Err(RedisError::RespDeserialize(
//             "integer value could't be hash key".to_string(),
//         )),
//         Value::BigNumber(_) => Err(RedisError::RespDeserialize(
//             "big number value could't be hash key".to_string(),
//         )),
//         Value::Double(_) => Err(RedisError::RespDeserialize(
//             "double value could't be hash key".to_string(),
//         )),
//         Value::Boolean(_) => Err(RedisError::RespDeserialize(
//             "boolean value could't be hash key".to_string(),
//         )),
//         Value::SimpleString(val) => std::str::from_utf8(val).map_err(|err| {
//             RedisError::RespDeserialize(format!(
//                 "error on parse Vec<u8> (from simple string) to str, {err}"
//             ))
//         }),
//         Value::BulkString(val) => std::str::from_utf8(val).map_err(|err| {
//             RedisError::RespDeserialize(format!(
//                 "error on parse Vec<u8> (from bulk string) to str, {err}"
//             ))
//         }),
//         Value::BulkError(val) => std::str::from_utf8(val).map_err(|err| {
//             RedisError::RespDeserialize(format!(
//                 "error on parse Vec<u8> (from bulk error) to str, {err}"
//             ))
//         }),
//         Value::SimpleError(val) => std::str::from_utf8(val).map_err(|err| {
//             RedisError::RespDeserialize(format!(
//                 "error on parse Vec<u8> (from simple error) to str, {err}"
//             ))
//         }),
//         Value::VerbatimString(encode, val) => {
//             if encode == "txt" {
//                 std::str::from_utf8(val).map_err(|err| {
//                     RedisError::RespDeserialize(format!(
//                         "error on parse Vec<u8> (from verbatim string) to str, {err}"
//                     ))
//                 })
//             } else {
//                 Err(RedisError::RespDeserialize(format!(
//                     "unsupported encoding type for verbatim string: {encode}"
//                 )))
//             }
//         }
//     }
// }
